//package com.demo.dialet;
//
//import java.util.ArrayList;
//import java.util.List;
//import java.util.Properties;
//
//import org.apache.ibatis.executor.Executor;
//import org.apache.ibatis.mapping.BoundSql;
//import org.apache.ibatis.mapping.MappedStatement;
//import org.apache.ibatis.mapping.ParameterMapping;
//import org.apache.ibatis.mapping.ResultMap;
//import org.apache.ibatis.mapping.SqlSource;
//import org.apache.ibatis.mapping.StatementType;
//import org.apache.ibatis.plugin.Interceptor;
//import org.apache.ibatis.plugin.Intercepts;
//import org.apache.ibatis.plugin.Invocation;
//import org.apache.ibatis.plugin.Plugin;
//import org.apache.ibatis.plugin.Signature;
//import org.apache.ibatis.session.ResultHandler;
//import org.apache.ibatis.session.RowBounds;
//import org.apache.log4j.Logger;
//
//
//@Intercepts({ @Signature(type = Executor.class,method="query", args={MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}) })
//public class PaginationInterceptor implements Interceptor {
//	// 日志对象
//	protected static Logger logger = Logger.getLogger(PaginationInterceptor.class);
//	private Dialect dialect = null;
//	private static final int MAPPED_STATEMENT_INDEX = 0;
//	private static final int PARAMETER_INDEX = 1;
//	private static final int ROWBOUNDS_INDEX = 2;
//
//	public Object intercept(Invocation invocation) throws Throwable {
//		Object[] invocationArgs = invocation.getArgs();
//	    MappedStatement ms = (MappedStatement)invocationArgs[0];
//
//	    if (ms.getStatementType() != StatementType.CALLABLE){
//	    	 PageLimit pl = PaginationSupport.getContext();
//	    	 String sql = ms.getBoundSql(invocationArgs[1]).getSql().trim();
//	    	 
//			if ((this.dialect.supportsLimit()) && (pl != null) && (pl.limited()) && (!pl.isLimited())) {
//				this.logger.debug("开始分页-目标SQL：" + sql.replaceAll("\n", "").replaceAll("\\s{2,}", " "));
//
//				if (pl.getTotalCount().intValue() == 0) {
//					rewriteCount(sql, ms, invocationArgs);
//					Integer totalCount = (Integer) ((List) invocation.proceed()).get(0);
//					pl.setTotalCount(totalCount);
//				}
//				if (pl.getId() != null){
//					rewriteOffset(sql, ms, invocationArgs);
//					Integer offset = (Integer) ((List) invocation.proceed()).get(0);
//					if (offset == null) offset = 0;
//					pl.setStartRowNo(offset + 1);
//				}
//				rewriteLimit(sql, ms, invocationArgs);
//				pl.setLimited(true);
//			} else if ((pl != null) && (pl.isOnlyGetTotalCnt())) {
//				this.logger.debug("查询记录数-目标SQL：" + sql.replaceAll("\n", "").replaceAll("\\s{2,}", " "));
//				rewriteCount(sql, ms, invocationArgs);
//				Integer totalCount = (Integer) ((List) invocation.proceed()).get(0);
//				pl.setTotalCount(totalCount);
//				PaginationSupport.getContext().setOnlyGetTotalCnt(false);
//			}
//	    }
//
//		return invocation.proceed();
//	}
//	
//	private void rewriteCount(String sql, MappedStatement ms, Object[] args) {
//		BoundSql boundSql = ms.getBoundSql(args[1]);
//		args[2] = new RowBounds(0, 2147483647);
//		args[0] = copyFromMappedStatement(ms, new BoundSqlSqlSource(copyFromBoundSql(ms, boundSql, this.dialect.getCountString(sql))), true);
//	}
//	
//	private void rewriteOffset(String sql, MappedStatement ms, Object[] args){
//		PageLimit pl = PaginationSupport.getContext();
//		BoundSql boundSql = ms.getBoundSql(args[1]);
//		args[2] = new RowBounds(0, 2147483647);
//		args[0] = copyFromMappedStatement(ms, new BoundSqlSqlSource(copyFromBoundSql(ms, boundSql, this.dialect.getOffsetString(sql, pl.getId(), pl.getName()))), true);
//	}
//
//	private void rewriteLimit(String sql, MappedStatement ms, Object[] args) {
//		PageLimit pl = PaginationSupport.getContext();
//
//		int offset = pl.getStartRowNo().intValue() - 1;
//		int limit = pl.getPageLength().intValue();
//
//		BoundSql boundSql = ms.getBoundSql(args[1]);
//
//		if (this.dialect.supportsLimitOffset()) {
//			sql = this.dialect.getLimitString(sql, offset, limit);
//			offset = 0;
//		} else {
//			sql = this.dialect.getLimitString(sql, 0, limit);
//		}
//
//		args[2] = new RowBounds(offset, 2147483647);
//
//		args[0] = copyFromMappedStatement(ms, new BoundSqlSqlSource(copyFromBoundSql(ms, boundSql, sql)), false);
//
//		pl.setLimited(true);
//	}
//
//	private BoundSql copyFromBoundSql(MappedStatement ms, BoundSql boundSql, String sql) {
//		BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), sql, boundSql.getParameterMappings(), boundSql.getParameterObject());
//		for (ParameterMapping mapping : boundSql.getParameterMappings()) {
//			String prop = mapping.getProperty();
//			if (boundSql.hasAdditionalParameter(prop)) {
//				newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop));
//			}
//		}
//		return newBoundSql;
//	}
//	
//	private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource, boolean countMappedStatement) {
//		MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource,
//				ms.getSqlCommandType());
//
//		builder.resource(ms.getResource());
//		builder.fetchSize(ms.getFetchSize());
//		builder.statementType(ms.getStatementType());
//		builder.keyGenerator(ms.getKeyGenerator());
//
//		if (ms.getKeyProperties() != null) {
//			for (String property : ms.getKeyProperties()) {
//				builder.keyProperty(property);
//			}
//
//		}
//
//		builder.timeout(ms.getTimeout());
//
//		builder.parameterMap(ms.getParameterMap());
//
//		if (countMappedStatement) {
//			List tmpList = new ArrayList();
//			tmpList.add(new ResultMap.Builder(ms.getConfiguration(), ms.getId() + "-count", Integer.class, new ArrayList()).build());
//			builder.resultMaps(tmpList);
//		} else {
//			builder.resultMaps(ms.getResultMaps());
//		}
//
//		builder.resultSetType(ms.getResultSetType());
//
//		builder.cache(ms.getCache());
//		builder.flushCacheRequired(ms.isFlushCacheRequired());
//		builder.useCache(ms.isUseCache());
//		return builder.build();
//	}
//	
//	public Object plugin(Object target) {
//		return Plugin.wrap(target, this);
//	}
//
//
//	public void setProperties(Properties properties) {
//		String dialectClass = properties.getProperty("dialectClass");
//		try {
//			this.dialect = ((Dialect) Class.forName(dialectClass).newInstance());
//		} catch (Exception e) {
//			throw new RuntimeException("分页-数据库类型创建出错:" + dialectClass, e);
//		}
//	}
//
//	public static class BoundSqlSqlSource implements SqlSource {
//		private BoundSql boundSql;
//
//		public BoundSqlSqlSource(BoundSql boundSqlParam) {
//			this.boundSql = boundSqlParam;
//		}
//
//		public BoundSql getBoundSql(Object parameterObject) {
//			return this.boundSql;
//		}
//	}
//
//}